/* 
 *   Copyright (c) 2021 Liu Bingyi
 *   MineSweeping is licensed under Mulan PSL v2.
 *   You can use this software according to the terms and conditions of the Mulan PSL v2.
 *   You may obtain a copy of Mulan PSL v2 at:
 *            http://license.coscl.org.cn/MulanPSL2
 *   THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 *   EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 *   MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 *   See the Mulan PSL v2 for more details.
 * 
 *   Author: LiuBingyi
 *   Email: cecillearofa@163.com
 *   Created at 2021/03/24 22:12:59
 */

package minesweeping;

public class MineSweepingDisplay {
    private Box[][] boxMapCache;
    private int[][] intMapCache;
    private MineSweepingBoard myMS;
    private boolean gameOver = true;
    private char[][] dispalyMap;
    private char[][] mistMap;
    private int mistCount;

    private String[] colBuff;// 储存列的字符值，目的是为了实现列坐标的竖直显示

    private int row;
    private int col;

    private static final char DISPLAY_SIGN_CLOSE = '\u25A0';
    private static final char DISPLAY_SIGN_SPACE = '\u25A1';
    private static final char DISPLAY_SIGN_MINE = '*';
    private static final char DISPLAY_SIGN_MARK = 'X';

    public static final byte DISPLAY_ORDER_OPEN = 0x01;
    public static final byte DISPLAY_ORDER_MARK = 0x02;

    public MineSweepingDisplay(MineSweepingBoard instance) {
        myMS = instance;

        boxMapCache = myMS.getBoardGrid();
        intMapCache = myMS.getBoardMap();

        row = myMS.getBoardRow();
        col = myMS.getBoardColumn();

        dispalyMap = new char[row][col];
        mistMap = new char[row][col];

        mistCount = row * col;

        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                dispalyMap[i][j] = DISPLAY_SIGN_CLOSE;
                mistMap[i][j] = DISPLAY_SIGN_CLOSE;
            }
        }
        colBuff = new String[col];
        for (int i = 0; i < col; i++) {
            colBuff[i] = String.valueOf(i);
        }
    }

    public char[][] flushmistMap() {
        if (myMS != null) {
            for (int i = 0; i < row; i++) {
                for (int j = 0; j < col; j++) { // 迷雾地图的默认值就是DISPLAY_SIGN_CLOSE
                    if (boxMapCache[i][j].isOpen()) { // 如果box已经被打开，则将其译码后的值放进迷雾地图中。
                        mistMap[i][j] = recoder(intMapCache[i][j]);
                    }
                    if (boxMapCache[i][j].isSeal()) { // 如果box已经被打开，则将其译码后的值放进迷雾地图中。
                        mistMap[i][j] = DISPLAY_SIGN_MARK;
                    }
                }
            }
            dispalyMap = mistMap;
        }
        return mistMap;
    }

    public char[][] flushLightMap() {
        char[][] lightMap = new char[row][col];
        if (myMS != null) {
            for (int i = 0; i < row; i++) {
                for (int j = 0; j < col; j++) {
                    lightMap[i][j] = recoder(intMapCache[i][j]);
                }
            }
            dispalyMap = lightMap;
        }
        return lightMap;
    }

    public void click(int a, int b) {
        if (a >= 0 && a < row && b >= 0 && b < col && isGameOver()) {
            if (!boxMapCache[a][b].isSeal()) {
                openBox(a, b);
                mistMap[a][b] = recoder(intMapCache[a][b]);
                if (intMapCache[a][b] == MineSweepingBoard.SIGNMINE) {
                    gameOver();
                }
                if (intMapCache[a][b] == MineSweepingBoard.SIGNSPACE) {
                    coverSpace(a, b);
                }
            } else {
                mistMap[a][b] = DISPLAY_SIGN_MARK;
            }
        }
    }

    public void click(Byte c, int a, int b) {
        if (c == DISPLAY_ORDER_MARK) {
            markMine(a, b);
        } else if (c == DISPLAY_ORDER_OPEN) {
            click(a, b);
        }
    }

    public void markMine(int a, int b) {
        if (boxMapCache[a][b].isSeal()) {
            boxMapCache[a][b].unsealBox();
            mistMap[a][b] = DISPLAY_SIGN_CLOSE;
        } else {
            boxMapCache[a][b].sealBox();
        }

    }

    public void printMap() {
        for (int i = Integer.toString(col).length(); i > 0; i--) {
            printForConsole("%3c", ' ');
            for (int j = 0; j < col; j++) {
                if (colBuff[j].length() >= i) {
                    printForConsole("%4c", colBuff[j].charAt(colBuff[j].length() - i));
                } else {
                    printForConsole("%4c", ' ');

                }
            }

            printForConsole("\n");
        }

        printForConsole("\n");
        for (int i = 0; i < row; i++) {
            printForConsole("%3d", i);
            for (int j = 0; j < col; j++) {
                printForConsole("%4c", dispalyMap[i][j]);
            }

            printForConsole("\n");
        }
    }

    private void coverSpace(int a, int b) {

        for (int i = a - 1; i <= a + 1; i++) {
            for (int j = b - 1; j <= b + 1; j++) {
                if (i >= 0 && j >= 0 && i < row && j < col && boxMapCache[i][j].isClose()) {
                    openBox(i, j);
                    if (intMapCache[i][j] == MineSweepingBoard.SIGNSPACE)
                        coverSpace(i, j);
                }
            }
        }

    }

    private char recoder(int src) {
        char r;
        switch (src) {
        case MineSweepingBoard.SIGNSPACE:
            r = DISPLAY_SIGN_SPACE;
            break;

        case MineSweepingBoard.SIGNMINE:
            r = DISPLAY_SIGN_MINE;
            break;

        default:
            r = Integer.toString(src).charAt(0);
            break;
        }
        return r;
    }

    public void openBox(int a, int b) {
        boxMapCache[a][b].openBox();
        mistCount--;
    }

    private void gameOver() {
        gameOver = false;
    }

    public boolean isGameOver() {
        if (mistCount == myMS.getBoardMine())
        {    gameOver();
            printForConsole("Successfully Sweeped Mines!ヽ(°▽°)ノ\n");
        }
        return gameOver;
    }

    private static void printForConsole(String format, Object ...arg) {
        System.out.printf(format, arg);
    }
}
